package com.ledtechdesign.service;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.StringBufferInputStream;
import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import java.util.Properties;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.ls.DOMImplementationLS;

import com.ledtechdesign.service.api.IAFCSServiceResult;

/**
 * Utility methods
 */
public class Utils {
	private static String base64code = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
			+ "abcdefghijklmnopqrstuvwxyz" + "0123456789" + "+/";

	static Log logger = LogFactory.getLog(Utils.class);

	public static String base64(String s) {
		StringBuilder encoded = new StringBuilder();
		int padding = (3 - (s.length() % 3)) % 3;
		s += "\0\0".substring(0, padding);
		for (int i = 0; i < s.length(); i += 3) {
			int j = (s.charAt(i) << 16) + (s.charAt(i + 1) << 8)
					+ s.charAt(i + 2);
			encoded.append(base64code.charAt((j >> 18) & 0x3f));
			encoded.append(base64code.charAt((j >> 12) & 0x3f));
			encoded.append(base64code.charAt((j >> 6) & 0x3f));
			encoded.append(base64code.charAt(j & 0x3f));
		}

		encoded.replace(encoded.length() - padding, encoded.length(), "=="
				.substring(0, padding));

		return encoded.toString();
	}

	public static IAFCSServiceResult getResult(Element root) throws Exception {
		logger.debug("called ***** getResult");
		return null;
	}

	static String hexString(byte[] bytes) {
		StringBuilder sb = new StringBuilder();

		for (byte b : bytes) {
			String x = Integer.toString((b >= 0 ? b : 256 + b), 16);
			if (x.length() == 1)
				sb.append("0");
			sb.append(x);
		}

		return sb.toString();
	}

	public static InputStream http_get(String url, Map<String, String> headers)
			throws Exception {

		logger.debug("http_get: " + url);
		if (headers != null)
			logger.debug(headers);

		URL req = new URL(url);
		HttpURLConnection connection = (HttpURLConnection) req.openConnection();

		if (headers != null) {
			for (Map.Entry<String, String> header : headers.entrySet())
				connection.addRequestProperty(header.getKey(), header
						.getValue());
		}

		int responseCode = connection.getResponseCode();

		if (responseCode == 200) {

			logger.debug("Content-Type: " + connection.getContentType());
			logger.debug("Content-Length: " + connection.getContentLength());

			return connection.getInputStream();

		} else if (responseCode == 302) {

			return http_get(connection.getHeaderField("Location"), headers);

		} else {
			String m = connection.getResponseMessage();
			Object c = connection.getContent();
			logger.debug("HTTP error " + responseCode);
			logger.debug("HTTP Message " + m);
			logger.debug(c);
			connection.disconnect();
			throw new Exception("GET " + url + " failed with status "
					+ responseCode + " and message" + m + " content" + c);
		}
	}

	public static InputStream http_post(String url, String data,
			Map<String, String> headers) throws Exception {
		logger.debug("http_post: " + url + " " + data);
		if (headers != null)
			logger.debug(headers);

		URL req = new URL(url);
		HttpURLConnection connection = (HttpURLConnection) req.openConnection();

		if (headers != null) {
			for (Map.Entry<String, String> header : headers.entrySet())
				connection.addRequestProperty(header.getKey(), header
						.getValue());
		}

		connection.setRequestMethod("POST");
		connection.setDoOutput(true);
		Writer writer = new OutputStreamWriter(connection.getOutputStream());
		writer.write(data);
		writer.flush();
		writer.close();
		connection.connect();

		int responseCode = connection.getResponseCode();

		if (responseCode == 200) {

			logger.debug("Content-Type: " + connection.getContentType());
			logger.debug("Content-Length: " + connection.getContentLength());

			return connection.getInputStream();

		} else if (responseCode == 302) {

			return http_post(connection.getHeaderField("Location"), data,
					headers);

		} else {

			logger.debug("HTTP error " + responseCode);
			logger.debug(connection.getContent());

			throw new Exception("POST " + url + " failed with status "
					+ responseCode);
		}

	}

	public static Element parseXML(InputStream input) throws Exception {
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		factory.setNamespaceAware(false);
		Document doc = factory.newDocumentBuilder().parse(input);
		return doc.getDocumentElement();
	}

	public static Element parseXML(String xmldata) throws Exception {
		return parseXML(new StringBufferInputStream(xmldata));
	}

	public static String printXML(Element root) throws Exception {
		DocumentBuilder builder = DocumentBuilderFactory.newInstance()
				.newDocumentBuilder();
		DOMImplementation impl = builder.getDOMImplementation();
		DOMImplementationLS ls = (DOMImplementationLS) impl.getFeature("LS",
				"3.0");

		return "Printing \n" + ls.createLSSerializer().writeToString(root);
	}

	public static String sign(String acctSecret, String sesSecret, String data)
			throws Exception {
		String bigSecret = acctSecret + ":" + sesSecret;
		SecretKeySpec sk = new SecretKeySpec(bigSecret.getBytes(), "HmacSHA1");
		Mac mac = Mac.getInstance("HmacSHA1");

		mac.init(sk);
		byte[] hmac = mac.doFinal(data.getBytes());
		return Utils.hexString(hmac);
	}
	//afcsje.properties
	public static Properties loadProperties(String propertyFileName) throws Exception {
		if(propertyFileName==null || propertyFileName.trim().equals("")){
			throw new Exception("Properties filename is null or eomty: >"+propertyFileName+"<");
		}
		if(propertyFileName.indexOf(".properties")==-1){
			propertyFileName+=".properties";
		}
		
		Properties prop = new Properties();
		FileInputStream fis;
		try {
			// option 1
			fis = new FileInputStream(propertyFileName);
			prop.load(fis);
		} catch (Exception e2) {
			try {
				// option 2
				prop.load(Thread.currentThread().getContextClassLoader()
						.getResourceAsStream(propertyFileName));

			} catch (Exception e) {
				// option 3
				java.net.URL url = ClassLoader
						.getSystemResource(propertyFileName);
				try {
					prop.load(url.openStream());
				} catch (IOException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
					
					throw new Exception("Could not Load Properties file "+
							propertyFileName+" ",e1);
					
				}
			}
		}
		
		return prop;

	}

}